# Makefile for Action Camera Architecture
# 运动相机多线程架构项目构建文件

# 项目信息
PROJECT_NAME = action_camera
VERSION = 1.0.0
TARGET = $(PROJECT_NAME)

# 目录结构
SRC_DIR = src
INC_DIR = include
BUILD_DIR = build
TEST_DIR = tests
DOC_DIR = docs

# 编译器设置
CC = gcc
CXX = g++
AR = ar

# 编译标志
CFLAGS = -std=c11 -Wall -Wextra -Wpedantic -Werror
CFLAGS += -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L
INCLUDES = -I$(INC_DIR)
LIBS = -lpthread -lm -lrt

# 调试/发布配置
DEBUG ?= 1
ifeq ($(DEBUG), 1)
    CFLAGS += -g -O0 -DDEBUG
    BUILD_TYPE = debug
else
    CFLAGS += -O2 -DNDEBUG
    BUILD_TYPE = release
endif

# 平台检测
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Linux)
    PLATFORM = linux
    LIBS += -ldl
endif
ifeq ($(UNAME_S), Darwin)
    PLATFORM = macos
endif

# 源文件收集
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
DEPENDS := $(OBJECTS:.o=.d)

# 测试文件
TEST_SOURCES := $(wildcard $(TEST_DIR)/*.c)
TEST_OBJECTS := $(TEST_SOURCES:$(TEST_DIR)/%.c=$(BUILD_DIR)/test_%.o)
TEST_TARGETS := $(TEST_OBJECTS:$(BUILD_DIR)/test_%.o=$(BUILD_DIR)/test_%)

# 默认目标
.PHONY: all clean test install doc help run
all: $(BUILD_DIR)/$(TARGET)

# 创建目录
$(BUILD_DIR):
	mkdir -p $(BUILD_DIR)

# 主程序构建
$(BUILD_DIR)/$(TARGET): $(OBJECTS) | $(BUILD_DIR)
	@echo "Linking $(TARGET)..."
	$(CC) $(OBJECTS) -o $@ $(LIBS)
	@echo "Built $(TARGET) for $(PLATFORM) ($(BUILD_TYPE))"

# 对象文件编译（包含依赖关系）
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
	@echo "Compiling $<..."
	$(CC) $(CFLAGS) $(INCLUDES) -MMD -MP -c $< -o $@

# 测试程序编译
$(BUILD_DIR)/test_%: $(BUILD_DIR)/test_%.o $(filter-out $(BUILD_DIR)/main.o, $(OBJECTS))
	@echo "Linking test $@..."
	$(CC) $^ -o $@ $(LIBS)

$(BUILD_DIR)/test_%.o: $(TEST_DIR)/%.c | $(BUILD_DIR)
	@echo "Compiling test $<..."
	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

# 运行测试
test: $(TEST_TARGETS)
	@echo "Running tests..."
	@for test in $(TEST_TARGETS); do \
		echo "Running $$test..."; \
		$$test || exit 1; \
	done
	@echo "All tests passed!"

# 运行主程序
run: $(BUILD_DIR)/$(TARGET)
	@echo "Running $(TARGET)..."
	./$(BUILD_DIR)/$(TARGET)

# 内存检查
memcheck: $(BUILD_DIR)/$(TARGET)
	@echo "Running memory check..."
	valgrind --leak-check=full --show-leak-kinds=all ./$(BUILD_DIR)/$(TARGET)

# 线程检查
threadcheck: $(BUILD_DIR)/$(TARGET)
	@echo "Running thread check..."
	valgrind --tool=helgrind ./$(BUILD_DIR)/$(TARGET)

# 静态库构建
lib: $(BUILD_DIR)/lib$(PROJECT_NAME).a

$(BUILD_DIR)/lib$(PROJECT_NAME).a: $(filter-out $(BUILD_DIR)/main.o, $(OBJECTS))
	@echo "Creating static library..."
	$(AR) rcs $@ $^

# 安装
install: $(BUILD_DIR)/$(TARGET)
	@echo "Installing $(TARGET)..."
	install -D $(BUILD_DIR)/$(TARGET) /usr/local/bin/$(TARGET)
	install -D $(INC_DIR)/*.h /usr/local/include/$(PROJECT_NAME)/

# 文档生成
doc:
	@echo "Generating documentation..."
	@if command -v doxygen >/dev/null 2>&1; then \
		doxygen Doxyfile; \
	else \
		echo "Doxygen not found, skipping documentation generation"; \
	fi

# 代码格式化
format:
	@echo "Formatting code..."
	@if command -v clang-format >/dev/null 2>&1; then \
		find $(SRC_DIR) $(INC_DIR) -name '*.c' -o -name '*.h' | xargs clang-format -i; \
	else \
		echo "clang-format not found, skipping formatting"; \
	fi

# 静态分析
analyze:
	@echo "Running static analysis..."
	@if command -v cppcheck >/dev/null 2>&1; then \
		cppcheck --enable=all --inconclusive $(SRC_DIR); \
	else \
		echo "cppcheck not found, skipping static analysis"; \
	fi

# 性能分析
profile: CFLAGS += -pg
profile: $(BUILD_DIR)/$(TARGET)
	@echo "Performance profiling enabled"

# 代码覆盖率
coverage: CFLAGS += --coverage
coverage: LIBS += --coverage
coverage: $(BUILD_DIR)/$(TARGET) test
	@echo "Generating coverage report..."
	@if command -v gcov >/dev/null 2>&1; then \
		gcov $(SOURCES); \
	else \
		echo "gcov not found, skipping coverage report"; \
	fi

# 打包
dist: clean
	@echo "Creating distribution package..."
	tar -czf $(PROJECT_NAME)-$(VERSION).tar.gz \
		$(SRC_DIR) $(INC_DIR) $(TEST_DIR) $(DOC_DIR) \
		Makefile README.md

# 清理
clean:
	@echo "Cleaning build files..."
	rm -rf $(BUILD_DIR)
	rm -f $(PROJECT_NAME)-*.tar.gz
	rm -f *.gcov *.gcda *.gcno

# 深度清理
distclean: clean
	rm -rf docs/html docs/latex

# 显示构建信息
info:
	@echo "Project: $(PROJECT_NAME) v$(VERSION)"
	@echo "Platform: $(PLATFORM)"
	@echo "Build Type: $(BUILD_TYPE)"
	@echo "Compiler: $(CC)"
	@echo "Flags: $(CFLAGS)"
	@echo "Includes: $(INCLUDES)"
	@echo "Libraries: $(LIBS)"
	@echo "Sources: $(SOURCES)"
	@echo "Objects: $(OBJECTS)"

# 帮助信息
help:
	@echo "Available targets:"
	@echo "  all        - Build the main program (default)"
	@echo "  test       - Build and run tests"
	@echo "  run        - Build and run the main program"
	@echo "  lib        - Build static library"
	@echo "  install    - Install the program system-wide"
	@echo "  doc        - Generate documentation with Doxygen"
	@echo "  format     - Format code with clang-format"
	@echo "  analyze    - Run static analysis with cppcheck"
	@echo "  memcheck   - Run memory check with Valgrind"
	@echo "  threadcheck- Run thread analysis with Valgrind"
	@echo "  profile    - Build with profiling enabled"
	@echo "  coverage   - Generate code coverage report"
	@echo "  dist       - Create distribution package"
	@echo "  clean      - Remove build files"
	@echo "  distclean  - Remove all generated files"
	@echo "  info       - Show build configuration"
	@echo "  help       - Show this help message"
	@echo ""
	@echo "Options:"
	@echo "  DEBUG=1    - Build in debug mode (default)"
	@echo "  DEBUG=0    - Build in release mode"
	@echo ""
	@echo "Examples:"
	@echo "  make              # Build in debug mode"
	@echo "  make DEBUG=0      # Build in release mode"
	@echo "  make test         # Build and run tests"
	@echo "  make run          # Build and run program"
	@echo "  make memcheck     # Check for memory leaks"

# 包含依赖文件
-include $(DEPENDS)

# 打印变量（调试用）
print-%:
	@echo $* = $($*)

# 强制重新构建
.PHONY: rebuild
rebuild: clean all

# 开发模式（自动重新构建）
dev:
	@echo "Development mode - watching for changes..."
	@while true; do \
		make all; \
		inotifywait -qre modify $(SRC_DIR) $(INC_DIR); \
	done